
import { PropertyMetadata } from "./editor";
import * as fs from 'fs';
import * as electron from 'electron'
import { project } from "./project";
import * as path from 'path'



export function createPropertyItemRenderer(metadata: PropertyMetadata, item: any): AbstractPropertyItemRenderer {
    let itemRenderer: AbstractPropertyItemRenderer;
    const propertyType = metadata.type;

    if (propertyType == 'string') {
        itemRenderer = new TextInputPropertyItemRenderer(metadata, item);
    }
    else if (propertyType == 'number') {
        itemRenderer = new NumberInputPropertyItemRenderer(metadata, item)
    }
    else if (propertyType == 'primarykey') {
        itemRenderer = new PrimaryKeyInputPropertyItemRenderer(metadata, item);
    }
    else if (propertyType == 'dropdown') {
        itemRenderer = new DropdownPropertyItemRenderer(metadata, item)
    }
    else if (propertyType == 'image') {
        itemRenderer = new ImageSelectPropertyItemRenderer(metadata, item);
    }
    else {
        throw 'never'
    }
    return itemRenderer;
}

export abstract class AbstractPropertyItemRenderer {

    private onSubmit: (from: any, to: any) => void
    protected from: any;
    protected view: HTMLElement;

    constructor(protected metadata: PropertyMetadata, protected item: any) {

    }

    setSubmitCallback(submit: (from: any, to: any) => void) {
        this.onSubmit = submit;
    }

    getView() {
        this.view = this.createView();
        this.initValue();
        return this.view;
    }

    private initValue() {
        const propertyKey = this.metadata.key;
        const value = this.item[propertyKey];
        this.updateView(value);
        this.from = this.convert(value);
    }

    protected submit(to: any) {
        if (this.from == to) {
            return;
        }
        to = this.convert(to);
        this.updateView(to);
        this.onSubmit(this.from, to);
        this.from = to;
    }





    protected convert(value: any) {
        return value;
    }


    public abstract updateView(value: any): void;

    protected abstract createView(): HTMLElement;
}


class TextInputPropertyItemRenderer extends AbstractPropertyItemRenderer {

    constructor(metadata: PropertyMetadata, item: any) {
        super(metadata, item);
    }

    createView() {
        const propertyValueInput = document.createElement("input");
        propertyValueInput.onblur = () => {
            const to = propertyValueInput.value;
            this.submit(to)
        }
        return propertyValueInput;
    }

    updateView(to: any) {
        (this.view as HTMLInputElement).value = to;
    }
}

class NumberInputPropertyItemRenderer extends AbstractPropertyItemRenderer {

    constructor(metadata: PropertyMetadata, item: any) {
        super(metadata, item);
    }


    createView() {
        const propertyValueInput = document.createElement("input");
        const propertyKey = this.metadata.key;
        propertyValueInput.onblur = () => {

            const to = propertyValueInput.value;
            this.submit(to);
        }
        return propertyValueInput;
    }

    updateView(to: any) {
        (this.view as HTMLInputElement).value = to;
    }

    convert(value: any) {
        return parseInt(value);
    }

}


class PrimaryKeyInputPropertyItemRenderer extends AbstractPropertyItemRenderer {

    constructor(metadata: PropertyMetadata, item: any) {
        super(metadata, item);
    }

    createView() {
        const propertyValueInput = document.createElement("input");
        propertyValueInput.disabled = true;
        return propertyValueInput;
    }

    updateView(to: any) {
        (this.view as HTMLInputElement).value = to;
    }

}


class DropdownPropertyItemRenderer extends AbstractPropertyItemRenderer {

    constructor(metadata: PropertyMetadata, item: any) {
        super(metadata, item);
    }

    createView() {

        const propertyValue = document.createElement("select");
        propertyValue.onchange = () => {
            const to = propertyValue.value;
            this.submit(to);
        }

        const propertyMetadata = this.metadata.options;
        if (propertyMetadata) {
            const filename = path.join(project.projectRoot, propertyMetadata.filename)
            const content = fs.readFileSync(filename, 'utf-8');
            const json = JSON.parse(content);
            const optionMetadatas = json[propertyMetadata.prefix];

            for (let optionMetadata of optionMetadatas) {
                const option1 = document.createElement("option");
                option1.value = optionMetadata.id.toString();
                option1.innerText = optionMetadata.name;
                propertyValue.appendChild(option1)
            }
        }
        return propertyValue;
    }

    convert(value: any) {
        return parseInt(value);
    }

    updateView(to: any) {
        (this.view as HTMLInputElement).value = to;
    }

}


class ImageSelectPropertyItemRenderer extends AbstractPropertyItemRenderer {

    private img: HTMLImageElement;

    constructor(metadata: PropertyMetadata, item: any) {
        super(metadata, item);
    }


    createView() {

        const container = document.createElement("div");
        const img = document.createElement('img');
        img.width = img.height = 48;
        this.img = img;
        const button = document.createElement("button");
        button.onclick = () => {
            const defaultPath = project.projectRoot;
            electron.remote.dialog.showOpenDialog({
                title: "select image",
                defaultPath,
                filters: [
                    { name: 'Images', extensions: ['jpg', 'png', "jpeg"] }
                ]
            }, (filenames) => {
                if (filenames) {
                    const filename = filenames[0];
                    // "a\b\c\d"  (split '\\' )=>  ["a","b","c","d"] (join '/' )=> "a/b/c/d"
                    const relativePath = path.relative(defaultPath, filename).split("\\").join("/");
                    this.submit(relativePath)
                }

            })
        }

        container.appendChild(img);
        container.appendChild(button)
        button.innerText = "修改图片";
        return container;;
    }

    updateView(to: any) {
        if (to) {
            const root = project.projectRoot;
            const src = path.join(root, to);
            this.img.src = src;
        }
        else {
            this.img.src = "";
        }

        // this.view.innerText = to;
    }


}

